use std::borrow::Borrow;
use std::collections::HashMap;
use std::hash::Hash;
use std::ops::Add;
use chrono::Local;
use fibers_http_server::Res;
use crate::codes::http::ResponseType::{JSON, TEXT};


pub struct Request{
    method:String,
    url:String,
    header:HashMap<String,String>,
    body:Vec<u8>,
    protocol:String,
}

impl Request {
    pub fn read_from_data(data:Vec<u8>) -> Option<Self> {
        let mut header = HashMap::new();
        let mut str_data = String::from_utf8(data).unwrap();
        let space = String::from("\r\n");
        let arr:Vec<&str> = str_data.split(space.as_str()).collect();

        let protocol = arr[0].to_string();
        let ps:Vec<&str> = protocol.split(" ").collect();
        if ps.len() != 3 {
            return None;
        }
        let method = ps[0].to_string();
        let url = ps[1].to_string();
        let protocol = ps[2].to_string();

        let mut body_index= 0;
        for i in 1..arr.len() {
            let onedata = arr[i];
            if onedata == "" {
                body_index = i+1;
                break;
            }

            let str = onedata.to_string();
            let one:Vec<&str>;
            if str.contains(": ") {
                one = str.splitn(2,": ").collect();
            } else {
                one = str.splitn(2,":").collect();
            }

            header.insert(one[0].to_string(),one[1].to_string());
        }

        let mut body = String::new();
        if body_index < arr.len() {
            for i in body_index..arr.len() {
                body = body.add(arr[i]);
            }
        }

        let result = Request{
            method,
            url,
            header,
            body: body.into_bytes(),
            protocol
        };

        Some(result)
    }
}

impl Request {
    pub fn get_header(&self,key:String) -> Option<String> {
        let res = self.header.get(key.as_str());
        match res {
            None=>None,
            Some(str)=> Some(str.clone())
        }
    }

    pub fn get_url(&self) -> &String {
        &self.url
    }

    pub fn get_body(&self) -> &Vec<u8> {
        &self.body
    }

    pub fn get_method(&self) -> &String {
        &self.method
    }

    pub fn to_tcp_data(&self) ->Vec<u8> {
        let mut result_str = String::new();
        result_str = result_str.add(self.method.as_str());
        result_str.push(' ');
        result_str = result_str.add(self.url.as_str());
        result_str.push(' ');
        result_str = result_str.add(self.protocol.as_str());
        result_str = result_str.add("\r\n"); //回车

        for (k,v) in self.header.borrow() {
            result_str = result_str.add(k.as_str());
            result_str.push(':');
            result_str.push(' ');
            result_str = result_str.add(v.as_str());
            result_str = result_str.add("\r\n");
        }

        result_str = result_str.add("\r\n");

        let mut result = result_str.into_bytes();
        result.append(&mut self.body.clone());

        result
    }

    pub fn set_header(&mut self,key:String,value:String) {
        self.header.insert(key,value);
    }

    pub fn headers(&mut self) -> &mut HashMap<String,String> {
        &mut self.header
    }

    pub fn method(&self) -> &str {
        self.method.as_str()
    }

    pub fn into_bytes(&self) -> Vec<u8> {
        let mut result_str = String::new();
        result_str = result_str.add(self.method.as_str());
        result_str = result_str.add(" ");
        result_str = result_str.add(self.url.to_string().as_str());
        result_str = result_str.add(" ");
        result_str = result_str.add(self.protocol.as_str());
        result_str = result_str.add("\r\n");

        for (k,v) in self.header.borrow() {
            if k.to_ascii_lowercase().as_str() == "host" {
                result_str = result_str.add("Host: 127.0.0.1");
                result_str = result_str.add("\r\n");
                continue;
            }
            result_str = result_str.add(k.as_str());
            result_str = result_str.add(": ");
            result_str = result_str.add(v.as_str());
            result_str = result_str.add("\r\n");
        }
        result_str = result_str.add("\r\n");

        let mut result = result_str.into_bytes();
        result.append(&mut self.body.clone());

        result
    }
}

pub enum ResponseType {
    JSON,
    TEXT,
    HTML,
}

impl ResponseType {
    pub fn to_string(&self) -> String {
        match self {
            JSON => String::from("application/json;charset:utf-8;"),
            TEXT => String::from("text/plain"),
            HTML=> String::from("text/html"),
        }
    }
}

pub trait ResponseData{
    fn response_data(&self)->Vec<u8>;
    fn response_type(&self) -> ResponseType;
}

impl ResponseData for String {
    fn response_data(&self) -> Vec<u8> {
        self.clone().into_bytes()
    }

    fn response_type(&self) -> ResponseType {
        TEXT
    }
}

impl ResponseData for serde_json::Value {
    fn response_data(&self) -> Vec<u8> {
        serde_json::to_string(self).unwrap().into_bytes()
    }

    fn response_type(&self) -> ResponseType {
        JSON
    }
}

#[derive(Clone)]
pub struct Response{
    protocol:String,
    status:u32,
    header:HashMap<String,String>,
    str_status:String,
    body:Vec<u8>
}

impl Response {
    pub fn ok<T>(body:T) -> Self where T:ResponseData {
        let mut response = Response{
            protocol: "HTTP/1.1".to_string(),
            status: 200,
            str_status:"OK".to_string(),
            header: Default::default(),
            body: body.response_data()
        };
        response.set_headers(body.response_type());

        response
    }

    pub fn err<T>(body:T) -> Self where T:ResponseData {
        let mut response = Response{
            protocol: "HTTP/1.1".to_string(),
            status: 500,
            str_status:"Internal Server Error".to_string(),
            header: Default::default(),
            body: body.response_data()
        };
        response.set_headers(body.response_type());

        response
    }

    pub fn not_found<T>(body:T) -> Self where T:ResponseData {
        let mut response = Response{
            protocol: "HTTP/1.1".to_string(),
            status: 404,
            str_status:"Not Found".to_string(),
            header: Default::default(),
            body: body.response_data()
        };
        response.set_headers(body.response_type());

        response
    }

    pub fn from_tcp_data(data:Vec<u8>) -> Option<Self> {
        let mut header = HashMap::new();
        let mut str_data = String::from_utf8(data).unwrap();
        let space = String::from("\r\n");
        let arr:Vec<&str> = str_data.split(space.as_str()).collect();

        let protocol = arr[0].to_string();
        let ps:Vec<&str> = protocol.splitn(3," ").collect();
        if ps.len() != 3 {
            return None;
        }
        let protocol = ps[0].to_string();
        let status:u32 = ps[1].to_string().parse().unwrap();
        let str_status = ps[2].to_string();

        let mut body_index= 0;
        for i in 1..arr.len() {
            let onedata = arr[i];
            if onedata == "" {
                body_index = i+1;
                break;
            }

            let str = onedata.to_string();
            let one:Vec<&str>;
            if str.contains(": ") {
                one = str.splitn(2,": ").collect();
            } else {
                one = str.splitn(2,":").collect();
            }

            header.insert(one[0].to_string(),one[1].to_string());
        }

        let mut body = String::new();
        if body_index < arr.len() {
            for i in body_index..arr.len() {
                body = body.add(arr[i]);
            }
        }

        let result = Response{
            header,
            str_status,
            body: body.into_bytes(),
            protocol,
            status
        };

        Some(result)
    }
}

impl Response {
    pub fn into_bytes(&self) -> Vec<u8> {
        let mut result_str = String::new();
        result_str = result_str.add(self.protocol.as_str());
        result_str = result_str.add(" ");
        result_str = result_str.add(self.status.to_string().as_str());
        result_str = result_str.add(" ");
        result_str = result_str.add(self.str_status.as_str());
        result_str = result_str.add("\r\n");

        for (k,v) in self.header.borrow() {
            result_str = result_str.add(k.as_str());
            result_str = result_str.add(": ");
            result_str = result_str.add(v.as_str());
            result_str = result_str.add("\r\n");
        }
        result_str = result_str.add("\r\n");

        let mut result = result_str.into_bytes();
        result.append(&mut self.body.clone());

        result
    }

    pub fn to_string(&self) -> String {
        let mut result_str = String::new();
        result_str = result_str.add(self.protocol.as_str());
        result_str = result_str.add(" ");
        result_str = result_str.add(self.status.to_string().as_str());
        result_str = result_str.add(" ");
        result_str = result_str.add(self.str_status.as_str());
        result_str = result_str.add("\r\n");

        for (k,v) in self.header.borrow() {
            result_str = result_str.add(k.as_str());
            result_str = result_str.add(": ");
            result_str = result_str.add(v.as_str());
            result_str = result_str.add("\r\n");
        }
        result_str = result_str.add("\r\n");

        result_str = result_str.add(String::from_utf8(self.body.clone()).unwrap().as_str());
        result_str
    }


    fn set_headers(&mut self,t:ResponseType) {
        let mut result: HashMap<String, String> = HashMap::new();
        result.insert("Server".to_string(), "sidecar-service/1.1".to_string());
        result.insert("Date".to_string(), Local::now().format("%Y-%m-%d %H:%M:%S").to_string());
        result.insert("Content-Type".to_string(),t.to_string());
        result.insert("Content-Length".to_string(),self.body.len().to_string());

        self.header = result;
    }

    pub fn set_header(&mut self,key:String,value:String) {
        self.header.insert(key,value);
    }

    pub fn header(&mut self) -> &mut HashMap<String,String> {
        &mut self.header
    }

    pub fn set_body(&mut self,data:Vec<u8>) {
        let l = data.len();
        self.body = data;
        self.set_header("Content-Length".to_string(),l.to_string());
    }
}




